package com.heima.stroke.configuration;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

//TODO:任务4.1-Rabbitmq配置
// RabbitConfig.java
@Configuration
public class RabbitConfig {
    // 行程超时队列
    public static final String STROKE_OVER_QUEUE = "STROKE_OVER_QUEUE";//名字是 "STROKE_OVER_QUEUE"，值也是 "STROKE_OVER_QUEUE"，代表 "行程超时队列" 的名称
    // 行程死信队列
    public static final String STROKE_DEAD_QUEUE = "STROKE_DEAD_QUEUE";//行程死信队列（处理过期消息的队列）
    // 行程超时队列交换器
    public static final String STROKE_OVER_QUEUE_EXCHANGE = "STROKE_OVER_QUEUE_EXCHANGE";//行程超时队列的交换器（消息的中转站）
    // 行程死信队列交换器
    public static final String STROKE_DEAD_QUEUE_EXCHANGE = "STROKE_DEAD_QUEUE_EXCHANGE";//行程死信队列的交换器
    // 行程超时交换器 ROUTINGKEY
    public static final String STROKE_OVER_KEY = "STROKE_OVER_KEY";//行程超时交换器的路由键（决定消息往哪个队列发）
    // 行程死信交换器 ROUTINGKEY
    public static final String STROKE_DEAD_KEY = "STROKE_DEAD_KEY";//行程死信交换器的路由键
    /**
     * 延迟时间 单位毫秒
     */
    private static final long DELAY_TIME = 1000 * 30;//值是 1000 * 30，也就是 30000 毫秒，等于 30 秒

    /**
     * 声明行程超时队列
     *
     * @return
     */
    @Bean//这是一个注解，告诉 Spring：这个方法会创建一个对象，需要交给 Spring 容器管理//可以理解为 "把这个队列注册到系统中"
    public Queue strokeOverQueue() {//定义了一个公开方法，返回值类型是 Queue（队列），方法名叫 strokeOverQueue//这个方法的作用是创建并返回 "行程超时队列"
        Map<String, Object> args = new HashMap<>();//创建了一个 HashMap（一种键值对集合），用来存放队列的额外配置参数//可以理解为 "准备一个配置项列表"
        // 配置死信交换机
        args.put("x-dead-letter-exchange", STROKE_DEAD_QUEUE_EXCHANGE);//给队列添加一个特殊配置：当消息过期或处理失败时，要转发到哪个死信交换机//这里指定了之前定义的 "行程死信队列交换器"
        // 配置死信 routing key
        args.put("x-dead-letter-routing-key", STROKE_DEAD_KEY);//配置死信路由键：消息转到死信交换机时，用哪个路由键//这里指定了之前定义的 "行程死信交换器 ROUTINGKEY"
        // 配置消息 TTL (30秒)
        args.put("x-message-ttl", DELAY_TIME);//配置消息的过期时间//这里用了之前定义的 30 秒（30000 毫秒），表示消息在这个队列里最多放 30 秒

        return QueueBuilder.durable(STROKE_OVER_QUEUE)//开始构建一个队列，durable 表示这个队列是持久化的（重启 RabbitMQ 后不会消失）//队列名称用了之前定义的 STROKE_OVER_QUEUE
                .withArguments(args)//把前面准备的那些额外配置（死信交换机、过期时间等）添加到队列中
                .build();//完成队列的构建并返回
                //这段代码创建了一个 "行程超时队列"，并给它设置了规则：消息在队列里最多存 30 秒。30 秒后如果还没被处理，就会被自动转到 "死信队列"。队列是持久化的，不会因为服务重启而消失
    }

    /**
     * 声明行程死信队列
     *
     * @return
     */
    @Bean
    public Queue strokeDeadQueue() {
        return QueueBuilder.durable(STROKE_DEAD_QUEUE).build();
    }//QueueBuilder：是 RabbitMQ 提供的一个工具类，用来构建队列。.durable(STROKE_DEAD_QUEUE)：表示创建一个持久化的队列，队列名称用之前定义的STROKE_DEAD_QUEUE 常量。.build()：完成队列的构建并返回

    /**
     * 创建行程超时队列交换器
     *
     * @return
     */
    @Bean
    DirectExchange strokeOverQueueExchange() {//定义了一个公开方法，返回值类型是DirectExchange（直接交换器），方法名叫strokeOverQueueExchange
        return new DirectExchange(STROKE_OVER_QUEUE_EXCHANGE);//DirectExchange是 RabbitMQ 中的一种交换器类型，它的特点是：只有消息的路由键和交换器与队列绑定的路由键完全匹配时，消息才会被转发到对应的队列
    }

    /**
     * 创建行程死信队列交换器
     *
     * @return
     */
    @Bean
    DirectExchange strokeDeadQueueExchange() {
        return new DirectExchange(STROKE_DEAD_QUEUE_EXCHANGE);
    }//DirectExchange（直接交换器）的特性是：只有当消息的路由键和交换器与队列绑定的路由键完全一致时，才会把消息转发到对应的队列。//创建一个直接交换器实例，交换器的名字使用我们之前定义的常量STROKE_DEAD_QUEUE_EXCHANGE（行程死信队列交换器）//返回一个绑定关系，将行程超时队列绑定到行程死信队列交换器，并指定路由键为STROKE_DEAD_KEY（行程死信交换器 ROUTINGKEY）

    /**
     * 行程超时队列绑定
     *
     * @return
     */
    @Bean
    Binding bindingStrokeOverDirect() {//定义一个公开方法，返回值是Binding（绑定关系），方法名叫bindingStrokeOverDirect。这个方法的作用是创建 "行程超时队列" 和对应的交换器之间的绑定关系
        return BindingBuilder.bind(strokeOverQueue())//BindingBuilder是 RabbitMQ 提供的绑定工具类。。.bind(strokeOverQueue())表示要绑定的目标是前面定义的 "行程超时队列"（调用了我们之前写的strokeOverQueue()方法获取队列对象）
                .to(strokeOverQueueExchange())//表示要绑定到哪个交换器，这里指定了前面定义的 "行程超时队列交换器"（调用strokeOverQueueExchange()方法获取交换器对象）
                .with(STROKE_OVER_KEY);//表示绑定的时候使用STROKE_OVER_KEY这个路由键//意思是：当交换器收到路由键为STROKE_OVER_KEY的消息时，会把消息转发到这个队列
                //简单说，这段代码的作用是建立 "连接关系"：让 "行程超时队列交换器" 和 "行程超时队列" 通过STROKE_OVER_KEY这个路由键关联起来。这样，当有消息发送到 "行程超时队列交换器" 且路由键匹配时，消息就会被正确送到 "行程超时队列" 中。
    }

    /**
     * 行程死信队列绑定
     *这段代码是用来将 "行程死信队列" 和 "行程死信队列交换器" 进行绑定的配置
     * @return
     */
    @Bean
    Binding bindingStrokeDeadDirect() {//定义一个公开方法，返回值是Binding（绑定关系），方法名叫bindingStrokeDeadDirect//这个方法的作用是创建 "行程死信队列" 和对应的死信交换器之间的绑定关系
        return BindingBuilder.bind(strokeDeadQueue())//使用BindingBuilder工具类，通过.bind(strokeDeadQueue())指定要绑定的目标是前面定义的 "行程死信队列"（调用strokeDeadQueue()方法获取队列对象）
                .to(strokeDeadQueueExchange())//表示要绑定到 "行程死信队列交换器"（调用strokeDeadQueueExchange()方法获取交换器对象）
                .with(STROKE_DEAD_KEY);//绑定使用的路由键是STROKE_DEAD_KEY//意思是：当死信交换器收到路由键为STROKE_DEAD_KEY的消息时，会把消息转发到这个死信队列
    }
}





